/* Copyright (C) 2011 clueless <clueless.mmopeon@gmail.com>
 *
 * This file is part of MMO Peon.
 *
 * MMO Peon is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * MMO Peon is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with MMO Peon.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __MMOPEON_STATEMACHINE_H
#define __MMOPEON_STATEMACHINE_H

#include <cstdint>
#include <vector>
/**
 * The bot uses a Finite State Machine (FSM) to make bot logic easy to maintain and
 * expand. Each 'state' is a certain action the bot should perform, each state has a
 * priority and is kept in a list sorted on that priority. Every time the FSM 'pulses'
 * it will iterate over the list of states and ask each state if it wants to run, when
 * a state indicates it is ready to run the FSM will execute that state and stop doing
 * anything until the next 'pulse'
 */


 /**
  * BaseState is a template for new states, any action you want the bot to perform should
  * be a derivative class from this base class.
  *
  * BaseState()     This constructor takes a priority for the state
  * Priority()      Returns the priority of this state, used by the FSM to sort states
  * Ready()         This function should be overwritten by the derivative state. It should
  *                 return true when the state has to run, and false otherwise. (e.g. if
                    you are currently in combat and this state handles combat it should
                    return true)
  * Enter()         This MAY be overwritten and is called only when a state was not yet
  *                 when the last pulse ran. You can use this to initialize your state.
  * Update()        This function should be overwritten and is called every pulse while
  *                 the state is active
  * Exit()          Like Enter this function only runs when the sate is being exited in
  *                 favor of another state
  */
class BaseState
{
    public:
        BaseState(uint32_t priority);
        virtual ~BaseState();
        uint32_t Priority() const;
        virtual bool Ready();
        virtual void Enter();
        virtual void Update();
        virtual void Exit();

    private:
        uint32_t priority;
};

bool CompareState(BaseState *a, BaseState *b);


/**
 * This is the finite state machine, all states are managed by this class
 *
 * Pulse()      Will loop over the states and select the appropriate state to run
 * AddState()   Adds a state to the list of states
 */
class StateMachine
{
    public:
        StateMachine();
        void Pulse();
        void AddState(BaseState* state);

    private:
        void SortStates();

        std::vector<BaseState *> states;
        BaseState* activeState;
        bool isSorted;
        bool haveActive;
};

#endif
